import { effect } from "@vue/reactivity";
import { ShapeFlags } from "@vue/shared";
import { createAppApi } from "./apiCreateApp"
import { createComponentInstance, setupComponent } from "./component";
import { normalizeVNode, Text } from "./vnode";

/**
 * 渲染器，vue3 中用户可以重写不同的渲染器适配不同的平台
 * 创建一个渲染器
 */
export function createRender(renderOptions) {
  const {
    createElement: hostCreateElement,
    createText: hostCreateText,
    insert: hostInsert,
    patchProp: hostPatchProp,
    remove: hostRemove,
    setElementText: hostSetElementText,
    setText: hostSetText
  } = renderOptions;

  const setupRenderEffect = (instance, container) => {
    /*
    创建一个 effect 在 effect 中调用 render 方法，
    这样 render 方法中拿到的数据会收集找个 effect 依赖，属性更新就会重新执行
    */
    instance.update = effect(function componentEffect() { // 每个组件对应一个 effect， vue3 是组件级别更新，数据更新就会重新执行对应组件的 effect 函数
      if (!instance.isMounted) { // 初次渲染
        const proxyToUse = instance.proxy;
        // 执行用户编写 setup 返回的函数执行
        const subTree = instance.subTree = instance.render.call(proxyToUse, proxyToUse);

        // 初始化子树
        patch(null, subTree, container);

        instance.isMounted = true;
        console.log('subTree', instance)
      } else { // 更新

      }
    })
  }

  //#region 处理组件
  const mountComponent = (initialVNode, container) => {
    // console.log(initialVNode, container);
    // 调用用户的 setup 函数执行，取得返回值，获取 render 函数返回的结果来进行渲染
    // 1. 创建实例
    const instance = initialVNode.component = createComponentInstance(initialVNode);
    // 2. 把数据解析到实例上
    setupComponent(instance);
    // 3. 创建一个 effect 让用户的setup返回的函数执行返回 render 函数执行
    setupRenderEffect(instance, container);
  }

  const processComponent = (n1, n2, container) => {
    if (n1 == null) { // 组件没有上一次的虚拟 DOM
      mountComponent(n2, container);
    } else {
      // 组件更新流程
    }
  }
  //#endregion

  //#region 处理元素
  const mountChildren = (children, container) => {
    for (let i = 0; i < children.length; i++) {
      const child = normalizeVNode(children[i]);
      patch(null, child, container);
    }
  }

  const mountElement = (vnode, container) => {
    // 递归渲染
    const { props, shapeFlag, type, children } = vnode;
    const el = vnode.el = hostCreateElement(type);
    
    if (props) {
      for (const key in props) {
        hostPatchProp(el, key, null, props[key]);
      }
    }
    if (shapeFlag & ShapeFlags.TEXT_CHILDREN) {
      hostSetElementText(el, children);
    } else if (shapeFlag & ShapeFlags.ARRAY_CHILDREN) {
      mountChildren(children, el);
    }
    hostInsert(el, container);
  }

  const processElement = (n1, n2, container) => {
    if (n1 == null) {
      mountElement(n2, container);
    } else {
      // 元素更新
    }
  }
  //#endregion

  //#region 文本处理
  const processText = (n1, n2, container) => {
    if (n1 == null) {
      hostInsert(n2.el = hostCreateText(n2.children), container);
    } else {
      // 文本更新
    }
  }
  //#endregion

  /**
   * 
   * @param n1 旧虚拟 DOM
   * @param n2 新虚拟 DOM
   * @param container 容器
   */
  const patch = (n1, n2, container) => {
    const { shapeFlag, type } = n2;

    switch(type) {
      case Text:
        console.log('文本', n1, n2, container);
        processText(n1, n2, container);
        break;
      default: 
        if (shapeFlag & ShapeFlags.ELEMENT) {
          console.log('元素', n1, n2, container);
          processElement(n1, n2, container);
        } else if (shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
          console.log('组件', n1, n2, container);
          processComponent(n1, n2, container);
        }
    }
  }

  const render = (vnode, container) => {
    // runtime-core 的核心
    patch(null, vnode, container);
  }

  return {
    createApp: createAppApi(render)
  }
 }